home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xpaint-2.1.1 / graphic.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  41KB  |  1,655 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1992, 1993, David Koblas (koblas@netcom.com)            | */
  3. /* |                                                                   | */
  4. /* | Permission to use, copy, modify, and to distribute this software  | */
  5. /* | and its documentation for any purpose is hereby granted without   | */
  6. /* | fee, provided that the above copyright notice appear in all       | */
  7. /* | copies and that both that copyright notice and this permission    | */
  8. /* | notice appear in supporting documentation.  There is no           | */
  9. /* | representations about the suitability of this software for        | */
  10. /* | any purpose.  this software is provided "as is" without express   | */
  11. /* | or implied warranty.                                              | */
  12. /* |                                                                   | */
  13. /* +-------------------------------------------------------------------+ */
  14.  
  15. #include <X11/Intrinsic.h>
  16. #include <X11/Shell.h>
  17. #include <X11/StringDefs.h>
  18. #include <X11/Xaw/Form.h>
  19. #include <X11/Xaw/Viewport.h>
  20. #include <X11/Xaw/Box.h>
  21. #include <X11/Xaw/Label.h>
  22. #include <X11/Xaw/Toggle.h>
  23. #include <X11/Xaw/SmeBSB.h>
  24. #include <X11/Xaw/Paned.h>
  25. #ifdef HAVE_COLTOG
  26. #include "ColToggle.h"
  27. #endif
  28. #include <stdio.h>
  29. #include <math.h>
  30.  
  31. #ifndef M_PI
  32. #define M_PI            3.14159265358979323846
  33. #endif
  34.  
  35. #ifndef NOSTDHDRS
  36. #include <stdlib.h>
  37. #include <unistd.h>
  38. #endif
  39.  
  40. #define LOOKUP_OUTSIDE
  41.  
  42. #include "Paint.h"
  43.  
  44. #include "xpaint.h"
  45. #include "palette.h"
  46. #include "misc.h"
  47. #include "menu.h"
  48. #include "text.h"
  49. #include "image.h"
  50. #include "cutCopyPaste.h"
  51. #include "rc.h"
  52.  
  53. #define DEFAULT_TITLE    "Untitled"
  54.  
  55. #define PATTERN(name)      \
  56.     (char *)CONCAT(name,_bits), CONCAT(name,_width), CONCAT(name,_height)
  57.  
  58. struct paintWindows {
  59.     Widget            paint;
  60.     struct paintWindows    *next;
  61.     void            *ldata;
  62.     Boolean            done;
  63. };
  64.  
  65. typedef struct {
  66.     Widget            paint;
  67.     Palette            *map;
  68.     Widget            primaryBox,  secondaryBox;
  69.     Widget            primaryList, secondaryList;
  70.     Widget            first, second;
  71. } LocalInfo;
  72.  
  73. /*
  74. **  Forward references
  75. */
  76. static void     makePaletteArea(LocalInfo*, RCInfo*);
  77. static void    editPatternCB(Widget, Widget);
  78. static void    deletePatternCB(Widget, Widget);
  79.  
  80. /*
  81. **  Begin menus
  82. */
  83.  
  84. static PaintMenuItem    fileMenu[] = {
  85. #define SAVE_ITEM 0
  86.     MI_SIMPLE("save"),
  87. #define SAVEAS_ITEM 1
  88.     MI_SIMPLE("saveas"),
  89. #define SAVER_ITEM 2
  90.     MI_SIMPLE("saveregion"),
  91. #define SAVE_CONFIG 3
  92.     MI_SIMPLE("saveconfig"),
  93. #define LOAD_CONFIG 4
  94.     MI_SIMPLE("loadconfig"),
  95. #define CLOSE_ITEM 5
  96.     MI_SIMPLE("close"),
  97. };
  98.  
  99. static PaintMenuItem    editMenu[] = {
  100. #define UNDO_ITEM    0
  101.     MI_SIMPLE("undo"),
  102.     MI_SEPERATOR(),
  103. #define CUT_ITEM    2
  104.     MI_SIMPLE("cut"),
  105. #define COPY_ITEM    3
  106.     MI_SIMPLE("copy"),
  107. #define PASTE_ITEM    4
  108.     MI_SIMPLE("paste"),
  109. #define CLEAR_ITEM    5
  110.     MI_SIMPLE("clear"),
  111.     MI_SEPERATOR(),
  112. #define DUP_ITEM    7
  113.     MI_SIMPLE("dup"),
  114. #define SELECT_ALL_ITEM    8
  115.     MI_SIMPLE("all"),
  116. #if 0
  117.     { "lock",   NULL, NULL, MF_NONE, 0, NULL },
  118.     { "unlock", NULL, NULL, MF_NONE, 0, NULL },
  119. #endif
  120. };
  121. static PaintMenuItem    rotateMenu[] = {
  122.     MI_SEPERATOR(),
  123.     MI_SIMPLE("rotate1"),
  124.     MI_SIMPLE("rotate2"),
  125.     MI_SIMPLE("rotate3"),
  126.     MI_SIMPLE("rotate4"),
  127.     MI_SIMPLE("rotate5"),
  128. };
  129.  
  130. static PaintMenuItem    regionMenu[] = {
  131. #define RG_FLIPX_ITEM    0
  132.     MI_SIMPLE("flipX"),
  133. #define RG_FLIPY_ITEM    1
  134.     MI_SIMPLE("flipY"),
  135.     MI_SEPERATOR(),
  136. #define RG_ROTATETO    3
  137.     MI_RIGHT("rotateTo", XtNumber(rotateMenu), rotateMenu),
  138. #define RG_ROTATE    4
  139.     MI_SIMPLE("rotate"),
  140.     MI_SEPERATOR(),
  141. #define RG_INVERT_ITEM    6
  142.     MI_SIMPLE("invert"),
  143. #define RG_SHARPEN_ITEM    7
  144.     MI_SIMPLE("sharpen"),
  145. #define RG_SMOOTH_ITEM    8
  146.     MI_SIMPLE("smooth"),
  147. #define RG_EDGE_ITEM    9
  148.     MI_SIMPLE("edge"),
  149. #define RG_EMBOSE_ITEM    10
  150.     MI_SIMPLE("emboss"),
  151. #define RG_OIL_ITEM    11
  152.     MI_SIMPLE("oil"),
  153.     MI_SEPERATOR(),
  154. #if 0
  155. #define RG_BOX    13
  156.     MI_SIMPLE("nudge"),
  157.     MI_SEPERATOR(),
  158. #define RG_RESET    15
  159. #endif
  160. #define RG_RESET    13
  161.     MI_SIMPLE("reset"),
  162. };
  163.  
  164. static PaintMenuItem    otherMenu[] = {
  165. #define    FAT_ITEM    0
  166.     MI_SIMPLE("fatbits"),
  167. #define    GRID_ITEM    1
  168.     MI_FLAG("grid", MF_CHECK),
  169. #define    SNAP_ITEM    2
  170.     MI_FLAG("snap", MF_CHECK),
  171. #define    CHSNAP_ITEM    3
  172.     MI_SIMPLE("snapSpacing"),
  173.     MI_SEPERATOR(),
  174. #define EDIT_BACKGROUND    5
  175.     MI_SIMPLE("background"),
  176.     MI_SEPERATOR(),
  177. #define    CHSIZE_ITEM    7
  178.     MI_SIMPLE("size"),
  179. #define    CHZOOM_ITEM    8
  180.     MI_SIMPLE("zoom"),
  181. };
  182.  
  183. static PaintMenuItem    helpMenu[] = {
  184.     MI_SIMPLECB("help", HelpDialog, "canvas"),
  185. };
  186.  
  187. static PaintMenuBar    menuBar[] = {
  188.     { None, "file",   XtNumber(fileMenu),   fileMenu },
  189.     { None, "edit",   XtNumber(editMenu),   editMenu },
  190.     { None, "region", XtNumber(regionMenu), regionMenu },
  191.     { None, "other",  XtNumber(otherMenu),  otherMenu },
  192.     { None, "help",   XtNumber(helpMenu),   helpMenu },
  193. };
  194.  
  195. static PaintMenuItem    paletteMenu[] = {
  196.     MI_SEPERATOR(),
  197.     MI_SIMPLECB("edit", (PaintMenuCallback)editPatternCB, NULL),
  198.     MI_SIMPLECB("remove", (PaintMenuCallback)deletePatternCB, NULL),
  199.     MI_SEPERATOR(),
  200.     MI_SIMPLECB("help", HelpDialog, "canvas.patBox"),
  201. };
  202.  
  203. /*
  204. **  End of menus
  205. */
  206.  
  207. static struct paintWindows    *head = NULL;
  208.  
  209. void GraphicRemove(Widget paint, XtPointer junk, XtPointer junk2)
  210. {
  211.     struct paintWindows    *cur = head, **prev = &head;
  212.  
  213.     while (cur != NULL && cur->paint != paint) {
  214.         prev = &cur->next;
  215.         cur = cur->next;
  216.     }
  217.  
  218.     if (cur == NULL)
  219.         return;
  220.  
  221.     *prev = cur->next;
  222.  
  223.     if (cur->done)
  224.         CurrentOp[1](cur->paint, cur->ldata);
  225.     XtFree((XtPointer)cur);
  226. }
  227.  
  228. static void destroyCallback(Widget paint, XtPointer data, XtPointer junk2)
  229. {
  230.     LocalInfo        *info = (LocalInfo *)data;
  231.     Colormap        cmap;
  232.     Palette            *map;
  233.  
  234.     XtVaGetValues(paint, XtNcolormap, &cmap, NULL);
  235.  
  236.     if ((map = PaletteFind(paint, cmap)) != NULL) 
  237.         PaletteDelete(map);
  238.     XtFree((XtPointer)info);
  239. }
  240.  
  241. static void realize(Widget paint, XtPointer ldataArg, XEvent *event, Boolean *junk)
  242. {
  243.     struct paintWindows    *cur = (struct paintWindows*)ldataArg;
  244.  
  245.     if (event->type == MapNotify) {
  246.         XtRemoveEventHandler(paint, StructureNotifyMask, False, realize, ldataArg);
  247.         if (CurrentOp != NULL && CurrentOp[0] != NULL)
  248.             cur->ldata = CurrentOp[0](paint);
  249.         cur->done = True;
  250.     }
  251. }
  252. void GraphicAdd(Widget paint)
  253. {
  254.      struct paintWindows    *new = XtNew(struct paintWindows);
  255.  
  256.     new->next  = head;
  257.     head       = new;
  258.     new->paint = paint;
  259.     new->ldata = NULL;
  260.     new->done  = False;
  261.  
  262.     if (XtIsRealized(paint)) {
  263.         if (CurrentOp != NULL && CurrentOp[0] != NULL)
  264.             new->ldata = CurrentOp[0](paint);
  265.         new->done = True;
  266.     } else {
  267.         XtAddEventHandler(paint, StructureNotifyMask, False, realize, (XtPointer)new);
  268.     }
  269.  
  270.     XtAddCallback(paint, XtNdestroyCallback, GraphicRemove, NULL);
  271. }
  272.  
  273.  
  274. void GraphicAll(void (*func)(), void *data)
  275. {
  276.     struct paintWindows    *cur;
  277.  
  278.     for (cur = head; cur != NULL; cur=cur->next) {
  279.         if (!cur->done)
  280.             continue;
  281.         func(cur->paint, data);
  282.     }
  283. }
  284. void GraphicSetOp(void (*stop)(Widget, void *), void *(*start)(Widget))
  285. {
  286.     struct paintWindows    *cur;
  287.  
  288.     for (cur = head; cur != NULL; cur=cur->next) {
  289.         if (stop != NULL)
  290.             stop(cur->paint, cur->ldata);
  291.         if (start != NULL)
  292.             cur->ldata = start(cur->paint);
  293.     }
  294. }
  295. void *GraphicGetData(Widget w)
  296. {
  297.     struct paintWindows    *cur;
  298.  
  299.     for (cur = head; cur != NULL; cur=cur->next)
  300.         if (cur->paint == w)
  301.             return cur->ldata;
  302.     return NULL;
  303. }
  304.  
  305. /*
  306. **  Pattern creation and chaning, utilitys.
  307. */
  308. #define PAT_MIN_WH    24
  309.  
  310. typedef struct {
  311.     Widget        paint;
  312.     Widget        widget, widget2;
  313.     int        width, height;
  314.     Pixmap        pixmap, shownPixmap;
  315.     Pixel        pixel;
  316.     LocalInfo    *li;
  317. } PatternInfo;
  318.  
  319. static void    patternUpdate(PatternInfo *info, Boolean isFirst)
  320. {
  321.     char        *w_fr, *w_fg, *w_pat;
  322.  
  323.     if (isFirst) {
  324.         w_fr  = XtNfillRule;
  325.         w_fg  = XtNforeground;
  326.         w_pat = XtNpattern;
  327.     } else {
  328.         w_fr  = XtNlineFillRule;
  329.         w_fg  = XtNlineForeground;
  330.         w_pat = XtNlinePattern;
  331.     }
  332.  
  333.     if (info->pixmap == None) {
  334.         XtVaSetValues(info->paint, w_fg, info->pixel, 
  335.                        w_fr, FillSolid, 
  336.                        NULL);
  337.     } else {
  338.         XtVaSetValues(info->paint, w_pat, info->pixmap, 
  339.                        w_fr, FillTiled, 
  340.                        NULL);
  341.     }
  342. }
  343.  
  344. static void    setPatternCallback(Widget icon, PatternInfo *info, XtPointer junk2)
  345. {
  346.     Widget    rg;
  347.     Boolean    state;
  348.  
  349.     XtVaGetValues(icon, XtNstate, &state, XtNradioGroup, &rg, NULL);
  350.  
  351.     if (state == False)
  352.         return;
  353.  
  354.     if (rg == info->li->primaryList || info->li->primaryList == icon)
  355.         patternUpdate(info, True);
  356.     else
  357.         patternUpdate(info, False);
  358. }
  359. static void     freePatternInfo(Widget icon, PatternInfo *info)
  360. {
  361.     if (info->pixmap != info->shownPixmap)
  362.         XFreePixmap(XtDisplay(icon), info->shownPixmap);
  363.     if (info->pixmap != None)
  364.         XFreePixmap(XtDisplay(icon), info->pixmap);
  365.  
  366.     XtFree((XtPointer)info);
  367. }
  368.  
  369. static void installPatternPixmap(PatternInfo *info, Pixmap pix)
  370. {
  371.     XtPointer    curPrimary, curSecondary;
  372.  
  373.     curPrimary   = XawToggleGetCurrent(info->li->primaryList);
  374.     curSecondary = XawToggleGetCurrent(info->li->secondaryList);
  375.  
  376.     if (curPrimary == (XtPointer)info)
  377.         XawToggleUnsetCurrent(info->li->primaryList);
  378.     if (curSecondary == (XtPointer)info)
  379.         XawToggleUnsetCurrent(info->li->secondaryList);
  380.  
  381.     XtVaSetValues(info->widget, XtNbitmap, pix, NULL);
  382.     XtVaSetValues(info->widget2, XtNbitmap, pix, NULL);
  383.  
  384.     if (curPrimary == (XtPointer)info)
  385.         XawToggleSetCurrent(info->li->primaryList, curPrimary);
  386.     if (curSecondary == (XtPointer)info)
  387.         XawToggleSetCurrent(info->li->secondaryList, curSecondary);
  388. }
  389.  
  390. static void editSolidOk(Widget paint, PatternInfo *info, XColor *col)
  391. {
  392.     LocalInfo    *l = info->li;
  393.  
  394.     StateShellBusy(paint, False);
  395.  
  396.     if (col == NULL)
  397.         return;
  398.  
  399.     if (!PaletteSetPixel(l->map, info->pixel, col)) {
  400.         /*
  401.         **  This will fail for because we are on a static screen
  402.         **   if it is a TrueColor screen change the "icon"
  403.         */
  404.         if (!l->map->isMapped) {
  405.             /*
  406.             **  TrueColor
  407.             */
  408.             Pixel    p = PaletteAlloc(l->map, col);
  409.             Display    *dpy = XtDisplay(paint);
  410.             GC    gc = XCreateGC(dpy, XtWindow(paint), 0, 0);
  411.             Pixmap    pix;
  412.             int    depth;
  413.  
  414.             XtVaGetValues(info->widget, XtNdepth, &depth, NULL);
  415.  
  416.             pix = XCreatePixmap(dpy, DefaultRootWindow(dpy), PAT_MIN_WH, PAT_MIN_WH, depth);
  417.             XSetForeground(dpy, gc, p);
  418.             XFillRectangle(dpy, pix, gc, 0, 0, PAT_MIN_WH, PAT_MIN_WH);
  419.  
  420.             info->pixel       = p;
  421.             installPatternPixmap(info, pix);
  422.  
  423.             XFreePixmap(dpy, info->shownPixmap);
  424.             info->shownPixmap = pix;
  425.  
  426.             XFreeGC(dpy, gc);
  427.         }
  428.     }
  429. }
  430.  
  431. static void    editPatternAction(Widget w, XEvent *event)
  432. {
  433.     PatternInfo    *info;
  434.  
  435.     XtVaGetValues(w, XtNradioData, &info, NULL);
  436.  
  437.     if (info->pixmap == None) {
  438.         LocalInfo    *l = (LocalInfo *)info->li;
  439.  
  440.         if (!l->map->readonly || !l->map->isMapped) {
  441.             StateShellBusy(l->paint, True);
  442.  
  443.             ColorEditor(l->paint, info->pixel, l->map, True,
  444.                 (XtCallbackProc)editSolidOk, (XtPointer)info);
  445.         }
  446.     } else {
  447.         void    PatternEdit(Widget, Pixmap, Widget);
  448.  
  449.         PatternEdit(info->paint, info->pixmap, w);
  450.     }
  451. }
  452.  
  453. static void    deletePatternCB(Widget mb, Widget w)
  454. {
  455.     LocalInfo    *li;
  456.     PatternInfo    *info, *ainfo;
  457.     Widget        parent;
  458.     WidgetList    children;
  459.     int        nchild;
  460.     Boolean        setFirst = False;
  461.     Boolean        actPrimary = False, actSecondary = False;
  462.  
  463.     XtVaGetValues(w, XtNradioData, &info, NULL);
  464.  
  465.     /*
  466.     **  Check to see if it is active
  467.     */
  468.     ainfo = (PatternInfo*)XawToggleGetCurrent(info->widget);
  469.     if (info == ainfo) {
  470.         XawToggleUnsetCurrent(info->widget);
  471.         actPrimary = True;
  472.     }
  473.     ainfo = (PatternInfo*)XawToggleGetCurrent(info->widget2);
  474.     if (info == ainfo) {
  475.         XawToggleUnsetCurrent(info->widget2);
  476.         actSecondary = True;
  477.     }
  478.  
  479.     /*  
  480.     **  Make sure there is enough widgets
  481.     */
  482.     XtVaGetValues(parent = XtParent(info->widget), 
  483.                 XtNnumChildren, &nchild, 
  484.                 XtNchildren, &children, 
  485.                 NULL);
  486.     if (nchild == 1) {
  487.         Notice(w, "You must have at least one entry");
  488.         return;
  489.     }
  490.  
  491.     li = info->li;
  492.     if (info->widget  == li->primaryList)
  493.         setFirst = True;
  494.  
  495.     XtDestroyWidget(info->widget);
  496.     XtDestroyWidget(info->widget2);
  497.  
  498.     if (setFirst) {
  499.         XtVaGetValues(parent, XtNchildren, &children, NULL);
  500.         if (children[0] == info->widget)
  501.             li->primaryList = children[1];
  502.         else
  503.             li->primaryList = children[0];
  504.         XtVaGetValues(li->primaryList, XtNradioData, &info, NULL);
  505.         li->secondaryList = info->widget2;
  506.     }
  507.     if (actPrimary) {
  508.         XtVaGetValues(li->primaryList, XtNradioData, &info, NULL);
  509.         XawToggleSetCurrent(li->primaryList, (XtPointer)info);
  510.     }
  511.     if (actSecondary) {
  512.         XtVaGetValues(li->secondaryList, XtNradioData, &info, NULL);
  513.         XawToggleSetCurrent(li->secondaryList, (XtPointer)info);
  514.     }
  515. }
  516.  
  517. static void    editPatternCB(Widget mb, Widget w)
  518. {
  519.     editPatternAction(w, NULL);
  520. }
  521.  
  522.  
  523. /*
  524. **   Special trick so that during creationg of the pattern box
  525. **    initialization can happen
  526. */
  527. static LocalInfo    *hiddenLocalInfo;
  528.  
  529. Widget AddPattern(Widget group, Widget paint, Pixmap pix, Pixel pxl)
  530. {
  531.     static XtTranslations    trans = None;
  532.     static GC        gc = None;
  533.     static Boolean        added = False;
  534.     Widget            parent, iconA, iconB, box;
  535.     PatternInfo        *info = XtNew(PatternInfo);
  536.     Display            *dpy = XtDisplay(group);
  537.     int            depth;
  538.     char            *nm = "pattern";
  539.  
  540.     if (!added) {
  541.         static XtActionsRec v = { "editPattern", (XtActionProc)editPatternAction };
  542.         XtAppAddActions(XtWidgetToApplicationContext(paint), &v, 1);
  543.         added = True;
  544.     }
  545.  
  546.     if (trans == None)
  547.         trans = XtParseTranslationTable("<BtnDown>,<BtnUp>: set() notify()\n<BtnDown>(2): editPattern()");
  548.  
  549.     if (XtClass(group) == toggleWidgetClass) {
  550.         PatternInfo    *tpi;
  551.  
  552.         parent = XtParent(group);
  553.         XtVaGetValues(group, XtNradioData, &tpi, NULL);
  554.         info->li = tpi->li;
  555. #ifdef HAVE_COLTOG
  556.     } else if (XtClass(group) == colToggleWidgetClass) {
  557.         PatternInfo    *tpi;
  558.  
  559.         parent = XtParent(group);
  560.         XtVaGetValues(group, XtNradioData, &tpi, NULL);
  561.         info->li = tpi->li;
  562. #endif
  563.     } else {
  564.         parent = group;
  565.         group  = None;
  566.         info->li = hiddenLocalInfo;
  567.     }
  568.  
  569.     box = parent;
  570.  
  571.     info->paint = paint;
  572.  
  573.     if (pix != None) {
  574.         GetPixmapWHD(dpy, pix, &info->width, &info->height, &depth);
  575.         info->pixmap    = pix;
  576.         if (info->width == 1 && info->height == 1) {
  577.             XImage    *xim = XGetImage(XtDisplay(paint), pix, 0, 0, 1, 1, AllPlanes, ZPixmap);
  578.             info->pixel  = XGetPixel(xim, 0, 0);
  579.             XDestroyImage(xim);
  580.  
  581.             info->pixmap = None;
  582.             pix = None;
  583.         }
  584.     } else {
  585.         info->pixel  = pxl;
  586.         info->pixmap = None;
  587.         XtVaGetValues(parent, XtNdepth, &depth, NULL);
  588.     }
  589.     if (info->pixmap == None)
  590.         nm = "solid";
  591.  
  592.     if (info->pixmap == None) {
  593.         /* XXX Getting a read only GC, and writing to it */
  594.         if (gc == None) gc = XtGetGC(paint, 0, 0);
  595.  
  596.         pix = XCreatePixmap(dpy, DefaultRootWindow(dpy), PAT_MIN_WH, PAT_MIN_WH, depth);
  597.         XSetForeground(dpy, gc, info->pixel);
  598.         XFillRectangle(dpy, pix, gc, 0, 0, PAT_MIN_WH, PAT_MIN_WH);
  599.     } else if (info->width < PAT_MIN_WH || info->height < PAT_MIN_WH) {
  600.         int    nw = (info->width < PAT_MIN_WH)  ? PAT_MIN_WH : info->width;
  601.         int    nh = (info->height < PAT_MIN_WH) ? PAT_MIN_WH : info->height;
  602.         int    x, y;
  603.  
  604.         if (gc == None) gc = XtGetGC(paint, 0, 0);
  605.  
  606.         pix = XCreatePixmap(dpy, DefaultRootWindow(dpy), nw, nh, depth);
  607.  
  608.         for (y = 0; y < nh; y += info->height)
  609.             for (x = 0; x < nw; x += info->width)
  610.                 XCopyArea(dpy, info->pixmap, pix, gc,
  611.                     0, 0, info->width, info->height, x, y);
  612.     }
  613.  
  614. #ifdef HAVE_COLTOG
  615.     if (info->pixmap == None) {
  616.         iconA = XtVaCreateManagedWidget(nm, colToggleWidgetClass, 
  617.                     info->li->primaryBox,
  618.                     XtNforeground, info->pixel,
  619.                     XtNradioGroup, info->li->primaryList,
  620.                     XtNtranslations, trans,
  621.                     XtNradioData, info,
  622.                     XtNisSolid, True,
  623.                     NULL);
  624.         iconB = XtVaCreateManagedWidget(nm, colToggleWidgetClass, 
  625.                     info->li->secondaryBox,
  626.                     XtNforeground, info->pixel,
  627.                     XtNradioGroup, info->li->secondaryList,
  628.                     XtNtranslations, trans,
  629.                     XtNradioData, info,
  630.                     XtNisSolid, True,
  631.                     NULL);
  632.     } else {
  633. #endif
  634.         iconA = XtVaCreateManagedWidget(nm, toggleWidgetClass, 
  635.                     info->li->primaryBox,
  636.                     XtNbitmap, pix,
  637.                     XtNradioGroup, info->li->primaryList,
  638.                     XtNtranslations, trans,
  639.                     XtNradioData, info,
  640.                     NULL);
  641.         iconB = XtVaCreateManagedWidget(nm, toggleWidgetClass, 
  642.                     info->li->secondaryBox,
  643.                     XtNbitmap, pix,
  644.                     XtNradioGroup, info->li->secondaryList,
  645.                     XtNtranslations, trans,
  646.                     XtNradioData, info,
  647.                     NULL);
  648. #ifdef HAVE_COLTOG
  649.     }
  650. #endif
  651.  
  652.     if (info->li->primaryList == None)
  653.         info->li->primaryList = iconA;
  654.     if (info->li->secondaryList == None)
  655.         info->li->secondaryList = iconB;
  656.     
  657.     XtAddCallback(iconA, XtNcallback, (XtCallbackProc)setPatternCallback, (XtPointer)info);
  658.     XtAddCallback(iconB, XtNcallback, (XtCallbackProc)setPatternCallback, (XtPointer)info);
  659.  
  660.     paletteMenu[1].data = (void*)iconA;
  661.     paletteMenu[2].data = (void*)iconA;
  662.     MenuPopupCreate(iconA, XtNumber(paletteMenu), paletteMenu);
  663.     paletteMenu[1].data = (void*)iconB;
  664.     paletteMenu[2].data = (void*)iconB;
  665.     MenuPopupCreate(iconB, XtNumber(paletteMenu), paletteMenu);
  666.  
  667.     info->widget  = iconA;
  668.     info->widget2 = iconB;
  669.  
  670.     info->shownPixmap = pix;
  671.     XtAddCallback(iconA, XtNdestroyCallback, (XtCallbackProc)freePatternInfo, (XtPointer)info);
  672.  
  673.     return iconA;
  674. }
  675. Widget    AddPatternInfo(void *piArg, Pixmap pix, Pixel pxl)
  676. {
  677.     PatternInfo    *pi = (PatternInfo *)piArg;
  678.  
  679.     return AddPattern(pi->widget, pi->paint, pix, pxl);
  680. }
  681. void    ChangePattern(void *iArg, Pixmap pix)
  682. {
  683.     PatternInfo    *info = (PatternInfo *)iArg;
  684.     int        depth;
  685.     Display        *dpy = XtDisplay(info->paint);
  686.     Pixmap        pfree1 = None, pfree2 = None;
  687.  
  688.     GetPixmapWHD(dpy, pix, &info->width, &info->height, &depth);
  689.  
  690.     if (info->pixmap != info->shownPixmap)
  691.         pfree1 = info->shownPixmap;
  692.     if (info->pixmap != None)
  693.         pfree2 = info->pixmap;
  694.     
  695.     info->pixmap = pix;
  696.  
  697.     if (info->width < PAT_MIN_WH || info->height < PAT_MIN_WH) {
  698.         int    nw = (info->width < PAT_MIN_WH)  ? PAT_MIN_WH : info->width;
  699.         int    nh = (info->height < PAT_MIN_WH) ? PAT_MIN_WH : info->height;
  700.         int    x, y;
  701.         GC    gc = XtGetGC(info->paint, 0, 0);
  702.  
  703.         pix = XCreatePixmap(dpy, DefaultRootWindow(dpy), nw, nh, depth);
  704.  
  705.         for (y = 0; y < nh; y += info->height)
  706.             for (x = 0; x < nw; x += info->width)
  707.                 XCopyArea(dpy, info->pixmap, pix, gc,
  708.                     0, 0, info->width, info->height, x, y);
  709.         XtReleaseGC(info->paint, gc);    
  710.     }
  711.  
  712.     installPatternPixmap(info, pix);
  713.  
  714.     info->shownPixmap = pix;
  715.  
  716.     if (pfree1 != None)
  717.         XFreePixmap(dpy, pfree1);
  718.     if (pfree2 != None)
  719.         XFreePixmap(dpy, pfree2);
  720. }
  721.  
  722. /*
  723. **  Save configuration 
  724. */
  725. static void saveConfigOkCallback(Widget il, LocalInfo *info, char *file)
  726. {
  727.     Widget        parent = XtParent(info->primaryList);
  728.     WidgetList    children;
  729.     int        nchildren;
  730.     int        i;
  731.     FILE        *fd;
  732.     Colormap    cmap;
  733.  
  734.     XtVaGetValues(parent, XtNchildren, &children, XtNnumChildren, &nchildren, NULL);
  735.     XtVaGetValues(GetShell(parent), XtNcolormap, &cmap, NULL);
  736.  
  737.     if (nchildren == 0) {
  738.         Notice(parent, "No information to save");
  739.         return;
  740.     }
  741.     
  742.     StateSetBusyWatch(True);
  743.  
  744.     if ((fd = fopen(file, "w")) == NULL) {
  745.         Notice(parent, "Unable to open file '%s' for writing", file);
  746.         return;
  747.     }
  748.     fprintf(fd, "reset\n\n");
  749.  
  750.     for (i = 0; i < nchildren; i++) {
  751.         PatternInfo    *pi;
  752.  
  753.         pi = NULL;
  754.         XtVaGetValues(children[i], XtNradioData, &pi, NULL);
  755.  
  756.         if (pi == NULL)
  757.             continue;
  758.  
  759.         if (pi->pixmap == None) {
  760.             XColor    col;
  761.             int    r,g,b;
  762.  
  763.             col.pixel = pi->pixel;
  764.             col.flags = DoRed|DoGreen|DoBlue;
  765.             XQueryColor(XtDisplay(parent), cmap, &col);
  766.             r = (col.red >> 8) & 0xff;
  767.             g = (col.green >> 8) & 0xff;
  768.             b = (col.blue >> 8) & 0xff;
  769.             fprintf(fd, "solid #%02x%02x%02x\n",r,g,b);
  770.         } else {
  771.             extern    void    WriteAsciiPNMfd(FILE *, Image *);
  772.  
  773.             Image    *image;
  774.             fprintf(fd, "pattern BeginData\n");
  775.             image = PixmapToImage(info->paint, pi->pixmap, cmap);
  776.             WriteAsciiPNMfd(fd, image);
  777.             ImageDelete(image);
  778.             fprintf(fd, "\nEndData\n");
  779.         }
  780.     }
  781.  
  782.     fclose(fd);
  783.  
  784.     StateSetBusyWatch(False);
  785. }
  786.  
  787. static void saveConfigCallback(Widget w, LocalInfo *info, XtPointer junk)
  788. {
  789.     GetFileName(info->paint, 2, ".XPaintrc", 
  790.             (XtCallbackProc)saveConfigOkCallback, (XtPointer)info);
  791. }
  792.  
  793. static void loadConfigOkCallback(Widget il, LocalInfo *info, char *file)
  794. {
  795.     RCInfo        *rcInfo = ReadRC(file);
  796.  
  797.     if (rcInfo == NULL) {
  798.         Notice(info->paint, "Unable to open file %s", file);
  799.         return;
  800.     }
  801.  
  802.     makePaletteArea(info, rcInfo);
  803.  
  804.     FreeRC(rcInfo);
  805. }
  806.  
  807. static void loadConfigCallback(Widget w, LocalInfo *info, XtPointer junk)
  808. {
  809.     GetFileName(info->paint, 3, ".XPaintrc", 
  810.             (XtCallbackProc)loadConfigOkCallback, (XtPointer)info);
  811. }
  812.  
  813. /*
  814. **  Pattern edit/add callback
  815. */
  816. static void addSolidOk(Widget w, LocalInfo *info, XColor *col)
  817. {
  818.     StateShellBusy(w, False);
  819.  
  820.     if (col != NULL) {
  821.         Pixel    pix   = PaletteAlloc(info->map, col);
  822.  
  823.         AddPattern(info->primaryList, info->paint, None, pix);
  824.     }
  825. }
  826.  
  827. static void addSolidCallback(Widget w, XtPointer wlArg, XtPointer junk2)
  828. {
  829.     LocalInfo    *info = (LocalInfo *)wlArg;
  830.     Widget        paint = info->paint;
  831.     Pixel        bg;
  832.  
  833.     StateShellBusy(paint, True);
  834.  
  835.     XtVaGetValues(paint, XtNbackground, &bg, NULL);
  836.  
  837.     ColorEditor(paint, bg, info->map, False, 
  838.             (XtCallbackProc)addSolidOk, (XtPointer)info);
  839. }
  840.  
  841. static void addPatternCallback(Widget w, XtPointer wlArg, XtPointer junk2)
  842. {
  843.     void    PatternEdit(Widget, Pixmap, Widget);
  844.     LocalInfo    *info = (LocalInfo *)wlArg;
  845.  
  846.     PatternEdit(info->paint, None, info->primaryList);
  847. }
  848. static void lookupPatternCallback(Widget w, XtPointer infoArg, XtPointer junk2)
  849. {
  850.     LocalInfo    *info = (LocalInfo *)infoArg;
  851.     int        nchildren, i;
  852.     WidgetList    children;
  853.     Widget        icon, list;
  854.     Colormap    cmap;
  855.     Pixel        p;
  856.     PatternInfo    *pi;
  857.  
  858.     DoGrabPixel(w, &p, &cmap);
  859.  
  860.     if (cmap != info->map->cmap) {
  861.         XColor    col;
  862.  
  863.         col.pixel = p;
  864.         col.flags = DoRed|DoGreen|DoBlue;
  865.         XQueryColor(XtDisplay(w), cmap, &col);
  866.         if (!PaletteLookupColor(info->map, &col, &p)) 
  867.             p = PaletteAlloc(info->map, &col);
  868.     }
  869.  
  870. #ifndef LOOKUP_OUTSIDE
  871.     if (XtParent(w) == info->primaryBox)
  872.         list = info->primaryList;
  873.     else 
  874.         list = info->secondaryList;
  875. #else
  876.     if (XtNameToWidget(XtParent(w), "viewport2.patternRack") == info->primaryBox)
  877.         list = info->primaryList;
  878.     else 
  879.         list = info->secondaryList;
  880. #endif
  881.  
  882.     XtVaGetValues(XtParent(list), 
  883.             XtNnumChildren, &nchildren,
  884.             XtNchildren, &children,
  885.             NULL);
  886.  
  887.     for (i = 0; i < nchildren; i++) {
  888.         pi = NULL;
  889.         XtVaGetValues(children[i], XtNradioData, &pi, NULL);
  890.         if (pi == NULL || pi->pixmap != None)
  891.             continue;
  892.  
  893.         if (pi->pixel == p) {
  894.             XawToggleSetCurrent(list, (XtPointer)pi);
  895.             return;
  896.         }
  897.     }
  898.  
  899.     icon = AddPattern(info->primaryList, info->paint, None, p);
  900.     XtVaGetValues(icon, XtNradioData, &pi, NULL);
  901.     XawToggleSetCurrent(list, (XtPointer)pi);
  902. }
  903.  
  904. /*
  905. **  Convert RC file information into the pattern box info
  906. */
  907. static void makePaletteArea(LocalInfo *info, RCInfo *rcInfo)
  908. {
  909.     Widget        firstIcon, icon;
  910.     Widget        pattern = info->secondaryBox;
  911.     XColor        col, rgb;
  912.     int        i, j;
  913.  
  914.     /*
  915.     **  Allocate the color entries
  916.     */
  917.     rcInfo->colorFlags  = (Boolean *)XtCalloc(sizeof(Boolean), 
  918.                             rcInfo->ncolors);
  919.     rcInfo->colorPixels = (Pixel   *)XtCalloc(sizeof(Pixel),   
  920.                             rcInfo->ncolors);
  921.     for (i = 0; i < rcInfo->ncolors; i++)
  922.         rcInfo->colorFlags[i] = False;
  923.  
  924.     for (i = 0; i < rcInfo->ncolors; i++) {
  925.         if (XLookupColor(XtDisplay(info->paint), info->map->cmap, 
  926.                 rcInfo->colors[i], &col, &rgb) || 
  927.             XParseColor(XtDisplay(info->paint), info->map->cmap, 
  928.                 rcInfo->colors[i], &col)) {
  929.             rcInfo->colorPixels[i] = PaletteAlloc(info->map, &col);
  930.             rcInfo->colorFlags[i]  = True;
  931.             for (j = 0; j < i; j++)
  932.                 if (rcInfo->colorPixels[i] == rcInfo->colorPixels[j])
  933.                     rcInfo->colorFlags[i]  = False;
  934.         }
  935.     }
  936.  
  937.     /*
  938.     **  Sneeky pass to AddPattern()
  939.     */
  940.     hiddenLocalInfo = info;
  941.  
  942.     firstIcon = pattern;
  943.  
  944.     for (i = 0; i < rcInfo->ncolors; i++) {
  945.         if (!rcInfo->colorFlags[i])
  946.             continue;
  947.  
  948.         icon = AddPattern(firstIcon, info->paint, None, rcInfo->colorPixels[i]);
  949.  
  950.         if (firstIcon == pattern) 
  951.             firstIcon = icon;
  952.     }
  953.  
  954.     for (i = 0; i < rcInfo->nimages; i++) {
  955.         Pixmap            pix;
  956.  
  957.         rcInfo->images[i]->refCount++;
  958.         pix = None;
  959.         ImageToPixmapCmap(rcInfo->images[i], info->paint, &pix, info->map->cmap);
  960.  
  961.         icon = AddPattern(firstIcon, info->paint, pix, 0);
  962.  
  963.         if (firstIcon == pattern) 
  964.             firstIcon = icon;
  965.     }
  966. }
  967.  
  968. /*
  969. **  First level menu callbacks.
  970. */
  971.  
  972. static void closeOkCallback(Widget shell, XtPointer junk, XtPointer junk2)
  973. {
  974.     XtDestroyWidget(shell);
  975. }
  976. static void closeCancelCallback(Widget shell, XtPointer junk, XtPointer junk2)
  977. {
  978. }
  979.  
  980. static void closeCallback(Widget w, XtPointer paintArg, XtPointer junk2)
  981. {
  982.     Widget    paint = (Widget)paintArg;
  983.     Boolean    flg;
  984.  
  985.     XtVaGetValues(paint, XtNdirty, &flg, NULL);
  986.     if (flg)
  987.         AlertBox(GetShell(paint), "Unsaved changes!\nDo you really wish to close?", 
  988.                 closeOkCallback, closeCancelCallback, NULL);
  989.     else
  990.         XtDestroyWidget(GetShell(paint));
  991. }
  992.  
  993. /*
  994. **
  995. */
  996. static void fatCallback(Widget w, XtPointer paint, XtPointer junk2)
  997. {
  998.     void    FatbitsEdit(Widget);
  999.  
  1000.     FatbitsEdit((Widget)paint);
  1001. }
  1002. static void gridCallback(Widget w, XtPointer paintArg, XtPointer junk2)
  1003. {
  1004.     Widget    paint = (Widget)paintArg;
  1005.     Boolean    v;
  1006.  
  1007.     XtVaGetValues(paint, XtNgrid, &v, NULL);
  1008.     v = !v;
  1009.     XtVaSetValues(paint, XtNgrid, v, NULL);
  1010.  
  1011.     MenuCheckItem(w, v);
  1012. }
  1013. static void snapCallback(Widget w, XtPointer paintArg, XtPointer junk2)
  1014. {
  1015.     Widget    paint = (Widget)paintArg;
  1016.     Boolean    v;
  1017.  
  1018.     XtVaGetValues(paint, XtNsnapOn, &v, NULL);
  1019.     v = !v;
  1020.     XtVaSetValues(paint, XtNsnapOn, v, NULL);
  1021.  
  1022.     MenuCheckItem(w, v);
  1023. }
  1024. /*
  1025. **  
  1026. */
  1027. static int  snapSpacing = 10;
  1028. static void changeSnapOkCallback(Widget paint, void *junk, XtPointer infoArg)
  1029. {
  1030.     TextPromptInfo    *info = (TextPromptInfo*)infoArg;
  1031.     int        v = atoi(info->prompts[0].rstr);
  1032.  
  1033.     if (v < 1 || v > 100) {
  1034.         Notice(paint,"Bad snap spacing.\nShould be between 2 and 100");
  1035.         return;
  1036.     }
  1037.         
  1038.     snapSpacing = v;
  1039.     XtVaSetValues(paint, XtNsnap, v, NULL);
  1040. }
  1041. static void changeSnapCallback(Widget w, XtPointer paintArg, XtPointer junk2)
  1042. {
  1043.     Widget paint = (Widget)paintArg;
  1044.     static TextPromptInfo        info;
  1045.     static struct textPromptInfo    value[1];
  1046.     static char    buf[10];
  1047.  
  1048.     sprintf(buf, "%d", snapSpacing);
  1049.  
  1050.     value[0].prompt = "Spacing:";
  1051.     value[0].str    = buf;
  1052.     value[0].len    = 4;
  1053.     info.prompts = value;
  1054.     info.title   = "Enter desired snap spacing";
  1055.     info.nprompt = 1;
  1056.  
  1057.     TextPrompt(paint, "linewidth", &info, changeSnapOkCallback, NULL, NULL);
  1058. }
  1059. static void sizeCallback(Widget w, XtPointer paintArg, XtPointer junk2)
  1060. {
  1061.     Widget    paint = (Widget)paintArg;
  1062.  
  1063.     SizeSelect(GetShell(paint), paint, NULL);
  1064. }
  1065. /*
  1066. **
  1067. */
  1068. static void zoomAddChild(Widget paint, int zoom)
  1069. {
  1070.     Cardinal    nc;
  1071.     Widget        t, box = XtParent(paint);
  1072.     WidgetList    children;
  1073.     int        dw, dh;
  1074.  
  1075.     /*
  1076.     **  1 child == just paint widget
  1077.     **  2 children paint widget + normal size view
  1078.     */
  1079.     XtVaGetValues(box, XtNchildren, &children, XtNnumChildren, &nc, NULL);
  1080.     XtVaGetValues(paint, XtNdrawWidth, &dw, XtNdrawHeight, &dh, NULL);
  1081.     if (nc == 1 && zoom > 1 && dw < 256 && dh < 256) {
  1082.         /*
  1083.         ** Add child
  1084.         */
  1085.         t = XtVaCreateManagedWidget("norm", paintWidgetClass, box,
  1086.                 XtNpaint, paint,
  1087.                 XtNzoom, 1,
  1088.                 NULL);
  1089.         GraphicAdd(t);
  1090.     } else if (nc != 1 && zoom <= 1) {
  1091.         /*
  1092.         ** Remove child
  1093.         */
  1094.         t = children[(children[0] == paint) ? 1 : 0];
  1095.         XtDestroyWidget(t);
  1096.     }
  1097. }
  1098.  
  1099. static void zoomOkCallback(Widget w, XtPointer paintArg, XtPointer infoArg)
  1100. {
  1101.         Widget          paint = (Widget)paintArg;
  1102.         TextPromptInfo  *info = (TextPromptInfo*)infoArg;
  1103.         int             zoom = atoi(info->prompts[0].rstr);
  1104.  
  1105.         if (zoom <= 0) {
  1106.                 Notice(paint, "Invalid zoom");
  1107.         } else {
  1108.                 XtVaSetValues(paint, XtNzoom, zoom, NULL);
  1109.         zoomAddChild(paint, zoom);
  1110.     }
  1111. }
  1112. void zoomCallback(Widget w, XtPointer paintArg, XtPointer junk2)
  1113. {
  1114.         static TextPromptInfo           info;
  1115.         static struct textPromptInfo    values[2];
  1116.         char                          buf[80];
  1117.         int                zoom;
  1118.     Widget                paint = (Widget)paintArg;
  1119.  
  1120.         info.nprompt = 1;
  1121.         info.prompts = values;
  1122.         info.title = "Change zoom factor for image";
  1123.         values[0].prompt = "Zoom: ";
  1124.         values[0].len    = 4;
  1125.         values[0].str    = buf;
  1126.  
  1127.         XtVaGetValues(paint, XtNzoom, &zoom, NULL);
  1128.         sprintf(buf, "%d", (int)zoom);
  1129.  
  1130.         TextPrompt(GetShell(paint), "zoomselect", &info, zoomOkCallback, NULL, paint);
  1131. }
  1132.  
  1133. /*
  1134. **
  1135. */
  1136. static void rotateTo(Widget w, XtPointer paintArg, XtPointer junk2)
  1137. {
  1138.     Widget        paint = (Widget)paintArg;
  1139.     float        t = M_PI / 4.0;
  1140.     pwMatrix    m;
  1141.     String        lbl;
  1142.  
  1143.     XtVaGetValues(w, XtNlabel, &lbl, NULL);
  1144.     t = atof(lbl);
  1145.     if (t == 0.0)
  1146.         return;
  1147.  
  1148.     t *= M_PI / 180.0;
  1149.  
  1150.     m[0][0] =  cos(t);
  1151.     m[0][1] = -sin(t);
  1152.     m[1][0] =  sin(t);
  1153.     m[1][1] =  cos(t);
  1154.     PwRegionAppendMatrix(paint, m);
  1155. }
  1156. static void rotateOkCallback(Widget paint, void *junk, XtPointer infoArg)
  1157. {
  1158.     TextPromptInfo    *info = (TextPromptInfo*)infoArg;
  1159.     float        t = atof(info->prompts[0].rstr) * M_PI / 180.0;
  1160.     pwMatrix    m;
  1161.  
  1162.     m[0][0] =  cos(t);
  1163.     m[0][1] = -sin(t);
  1164.     m[1][0] =  sin(t);
  1165.     m[1][1] =  cos(t);
  1166.     PwRegionAppendMatrix(paint, m);
  1167. }
  1168. static void rotate(Widget w, XtPointer paintArg, XtPointer junk2)
  1169. {
  1170.     Widget paint = (Widget)paintArg;
  1171.     static TextPromptInfo        info;
  1172.     static struct textPromptInfo    value[1];
  1173.     static char    buf[10];
  1174.  
  1175.     sprintf(buf, "%d", snapSpacing);
  1176.  
  1177.     value[0].prompt = "Angle (in Degrees):";
  1178.     value[0].str    = buf;
  1179.     value[0].len    = 4;
  1180.     info.prompts = value;
  1181.     info.title   = "Enter desired rotation";
  1182.     info.nprompt = 1;
  1183.  
  1184.     TextPrompt(paint, "linewidth", &info, rotateOkCallback, NULL, NULL);
  1185. }
  1186. static void resetMat(Widget w, XtPointer paintArg, XtPointer junk2)
  1187. {
  1188.     pwMatrix    m;
  1189.  
  1190.     m[0][0] = m[1][1] = 1;
  1191.     m[1][0] = m[0][1] = 0;
  1192.  
  1193.     PwRegionReset((Widget)paintArg, True);
  1194. }
  1195. static void nudgeBox(Widget w, XtPointer paintArg, XtPointer junk2)
  1196. {
  1197.     /* RegionBox((Widget)paintArg); */
  1198. }
  1199. static void prCallback(Widget paint, Widget w, Boolean flag)
  1200. {
  1201.     XtVaSetValues(w, XtNsensitive, flag, NULL);
  1202. }
  1203.  
  1204. /*
  1205. **  Background changer
  1206. */
  1207. static void changeBgOk(Widget w, Palette *map, XColor *col)
  1208. {
  1209.     StateShellBusy(w, False);
  1210.  
  1211.     if (col != NULL) {
  1212.         Pixel    pix   = PaletteAlloc(map, col);
  1213.         XtVaSetValues(w, XtNbackground, pix, NULL);
  1214.     }
  1215. }
  1216.  
  1217. static void changeBackground(Widget w, XtPointer paintArg, XtPointer junk2)
  1218. {
  1219.     Widget        paint = (Widget)paintArg;
  1220.     Colormap    cmap;
  1221.     Pixel        bg;
  1222.     Palette        *map;
  1223.  
  1224.     StateShellBusy(paint, True);
  1225.  
  1226.     XtVaGetValues(GetShell(paint), XtNcolormap, &cmap, NULL);
  1227.     XtVaGetValues(paint, XtNbackground, &bg, NULL);
  1228.     map = PaletteFind(paint, cmap);
  1229.  
  1230.     ColorEditor(paint, bg, map, 
  1231.             False, (XtCallbackProc)changeBgOk, (XtPointer)map);
  1232. }
  1233.  
  1234. /*
  1235. **  Start of graphic window creation routines
  1236. */
  1237.  
  1238. Widget makeGraphicShell(Widget wid)
  1239. {
  1240.     Arg        args[20];
  1241.     int        nargs = 0;
  1242.     Widget        shell;
  1243.  
  1244.     XtSetArg(args[nargs], XtNtitle, DEFAULT_TITLE);        nargs++;
  1245.     XtSetArg(args[nargs], XtNiconName, DEFAULT_TITLE);    nargs++;
  1246.  
  1247.     shell = XtAppCreateShell("Canvas", "Canvas", 
  1248.             topLevelShellWidgetClass, XtDisplay(GetToplevel(wid)),
  1249.             args, nargs);
  1250.  
  1251.     return shell;
  1252. }
  1253.  
  1254. static Widget mkPatternArea(Widget parent, Widget left, char *name, Widget *pform, LocalInfo *info)
  1255. {
  1256.     Widget    form, label, pattern, vport, lookup;
  1257.  
  1258.     form = XtVaCreateManagedWidget("patternRackForm", 
  1259.             formWidgetClass, parent,
  1260.             XtNborderWidth, 0,
  1261.             XtNfromHoriz, left,
  1262.             XtNleft, XtChainLeft,
  1263.             XtNright, XtChainLeft,
  1264.             NULL);
  1265.     if (pform != NULL)
  1266.         *pform = form;
  1267.     label = XtVaCreateManagedWidget(name, labelWidgetClass, form,
  1268.             XtNborderWidth, 0,
  1269.             NULL);
  1270. #ifdef LOOKUP_OUTSIDE
  1271.     lookup = XtVaCreateManagedWidget("lookup",
  1272.                 commandWidgetClass, form,
  1273.                 XtNfromHoriz, label,
  1274.                 NULL);
  1275. #else
  1276.     lookup = label;
  1277. #endif
  1278.  
  1279.     vport = XtVaCreateManagedWidget("viewport2",
  1280.             viewportWidgetClass, form,
  1281.             XtNallowVert, True,
  1282.             XtNuseBottom, True,
  1283.             XtNuseRight, True,
  1284.             XtNfromVert, lookup,
  1285.             NULL);
  1286.     pattern = XtVaCreateWidget("patternRack",
  1287.             boxWidgetClass, vport,
  1288.             NULL);
  1289. #ifndef LOOKUP_OUTSIDE
  1290.     lookup = XtVaCreateManagedWidget("lookup",
  1291.                 commandWidgetClass, pattern,
  1292.                 NULL);
  1293. #endif
  1294.  
  1295.     XtAddCallback(lookup, XtNcallback, lookupPatternCallback, (XtPointer)info);
  1296.  
  1297.     return pattern;
  1298. }
  1299.  
  1300. Widget graphicCreate(Widget shell, int width, int height, int zoom, Pixmap pix, Colormap cmap)
  1301. {
  1302.     Widget            form, viewport, pattern, bar;
  1303.     Widget            pane, pane1, pform;
  1304.     Widget            paint;
  1305.     Widget            icon, firstIcon;
  1306.     Widget            add, edit;
  1307.     WidgetList        child;
  1308.     int            nchild;
  1309.     RCInfo            *rcInfo;
  1310.     Palette            *map;
  1311.     int            i, j;
  1312.     int            depth;
  1313.     LocalInfo        *info = XtNew(LocalInfo);
  1314.     PatternInfo        *pData;
  1315.  
  1316.     /*
  1317.     **  Menu Bar
  1318.     */
  1319.  
  1320.     if (cmap == None) {
  1321.         map = PaletteCreate(shell);
  1322.         cmap = map->cmap;
  1323.     } else {
  1324.         map = PaletteFind(shell, cmap);
  1325.     }
  1326.     depth = map->depth;
  1327.     XtVaSetValues(shell, XtNcolormap, cmap, NULL);
  1328.  
  1329.     PaletteAddUser(map, shell);
  1330.  
  1331.     info->map = map;
  1332.  
  1333.     pane = XtVaCreateManagedWidget("pane", 
  1334.             panedWidgetClass, shell,
  1335.             NULL);
  1336.  
  1337.     rcInfo = ReadDefaultRC();
  1338.  
  1339.     /*
  1340.     **  Menu area
  1341.     */
  1342.     form = XtVaCreateManagedWidget("form1", 
  1343.             formWidgetClass, pane,
  1344.             NULL);
  1345.     bar = MenuBarCreate(form, XtNumber(menuBar), menuBar);
  1346.     XtVaSetValues(form, XtNshowGrip, False, NULL);
  1347.  
  1348.     /*
  1349.     **  Drawing Area
  1350.     */
  1351.     viewport = XtVaCreateWidget("viewport",
  1352.             viewportWidgetClass, pane,
  1353.             XtNfromVert, bar,
  1354.             XtNallowVert, True,
  1355.             XtNallowHoriz, True,
  1356.             XtNuseBottom, True,
  1357.             XtNuseRight, True,
  1358.             XtNtop, XtChainTop,
  1359.             NULL);
  1360.  
  1361.     /*
  1362.     **  Custom Drawing Widget here
  1363.     **   First read the file and convert to a bitmap
  1364.     */
  1365.     pane1 = XtVaCreateWidget("paintBox", 
  1366.             boxWidgetClass, viewport,
  1367.             XtNbackgroundPixmap, GetBackgroundPixmap(viewport),
  1368.             NULL);
  1369.  
  1370.     /*
  1371.     **  Try and do something nice for the user
  1372.     */
  1373.     if (zoom == -1 && width <= 64 && height <= 64) {
  1374.         int    wth = width;
  1375.         int    hth = height;
  1376.         if (pix != None) 
  1377.             GetPixmapWHD(XtDisplay(pane1), pix, &wth, &hth, NULL);
  1378.         if (wth <= 64 && hth <= 64 && wth != 0 && hth != 0)
  1379.             zoom = 6;
  1380.     }
  1381.  
  1382.     paint = XtVaCreateManagedWidget("paint",
  1383.             paintWidgetClass, pane1,
  1384.             XtNdrawWidth, width,
  1385.             XtNdrawHeight, height,
  1386.             XtNzoom, zoom,
  1387.             XtNpixmap, pix,
  1388.             XtNcolormap, cmap,
  1389.             XtNallowResize, True,
  1390.             XtNshowGrip, False,
  1391.             NULL);
  1392.     XtSetKeyboardFocus(pane, paint);
  1393.     zoomAddChild(paint, zoom);
  1394.     info->paint = paint;
  1395.     OperationSetPaint(paint);
  1396.     ccpAddStdPopup(paint);
  1397.  
  1398.     XtManageChild(pane1);
  1399.     XtManageChild(viewport);
  1400.  
  1401.     XtAddCallback(fileMenu[SAVE_CONFIG].widget,
  1402.             XtNcallback, (XtCallbackProc)saveConfigCallback, (XtPointer)info);
  1403.     XtAddCallback(fileMenu[LOAD_CONFIG].widget,
  1404.             XtNcallback, (XtCallbackProc)loadConfigCallback, (XtPointer)info);
  1405.  
  1406.     ccpAddUndo(editMenu[UNDO_ITEM].widget, paint);
  1407.     ccpAddCut(editMenu[CUT_ITEM].widget, paint);
  1408.     ccpAddCopy(editMenu[COPY_ITEM].widget, paint);
  1409.     ccpAddPaste(editMenu[PASTE_ITEM].widget, paint);
  1410.     ccpAddClear(editMenu[CLEAR_ITEM].widget, paint);
  1411.     ccpAddDuplicate(editMenu[DUP_ITEM].widget, paint);
  1412.  
  1413.     XtAddCallback(editMenu[SELECT_ALL_ITEM].widget,
  1414.             XtNcallback, StdSelectAllCallback, (XtPointer)paint);
  1415.     XtAddCallback(fileMenu[SAVEAS_ITEM].widget,
  1416.             XtNcallback, StdSaveAsFile, (XtPointer)paint);
  1417.     XtAddCallback(fileMenu[SAVE_ITEM].widget,
  1418.             XtNcallback, StdSaveFile, (XtPointer)paint);
  1419.     
  1420.     ccpAddSaveRegion(fileMenu[SAVER_ITEM].widget, paint);
  1421.  
  1422.     XtAddCallback(fileMenu[CLOSE_ITEM].widget,
  1423.             XtNcallback, closeCallback, (XtPointer)paint);
  1424.     XtAddCallback(otherMenu[GRID_ITEM].widget,
  1425.             XtNcallback, gridCallback, (XtPointer)paint);
  1426.     XtAddCallback(otherMenu[SNAP_ITEM].widget,
  1427.             XtNcallback, snapCallback, (XtPointer)paint);
  1428.     XtAddCallback(otherMenu[CHSNAP_ITEM].widget,
  1429.             XtNcallback, changeSnapCallback, (XtPointer)paint);
  1430.     XtAddCallback(otherMenu[FAT_ITEM].widget,
  1431.             XtNcallback, fatCallback, (XtPointer)paint);
  1432.     XtAddCallback(otherMenu[CHSIZE_ITEM].widget,
  1433.             XtNcallback, sizeCallback, (XtPointer)paint);
  1434.     XtAddCallback(otherMenu[CHZOOM_ITEM].widget,
  1435.             XtNcallback, zoomCallback, (XtPointer)paint);
  1436.     XtAddCallback(otherMenu[EDIT_BACKGROUND].widget,
  1437.             XtNcallback, changeBackground, (XtPointer)paint);
  1438.  
  1439.     ccpAddRegionFlipX(regionMenu[RG_FLIPX_ITEM].widget, paint);
  1440.     ccpAddRegionFlipY(regionMenu[RG_FLIPY_ITEM].widget, paint);
  1441.     ccpAddRegionInvert(regionMenu[RG_INVERT_ITEM].widget, paint);
  1442.     ccpAddRegionSharpen(regionMenu[RG_SHARPEN_ITEM].widget, paint);
  1443.     ccpAddRegionSmooth(regionMenu[RG_SMOOTH_ITEM].widget, paint);
  1444.     ccpAddRegionEdge(regionMenu[RG_EDGE_ITEM].widget, paint);
  1445.     ccpAddRegionEmbose(regionMenu[RG_EMBOSE_ITEM].widget, paint);
  1446.     ccpAddRegionOilPaint(regionMenu[RG_OIL_ITEM].widget, paint);
  1447.  
  1448.     for (i = 0; i < XtNumber(rotateMenu); i++) {
  1449.         if (rotateMenu[i].name[0] == '\0')
  1450.             continue;
  1451.  
  1452.         XtAddCallback(rotateMenu[i].widget, XtNcallback, 
  1453.                     (XtCallbackProc)rotateTo, (XtPointer)paint);
  1454.         XtAddCallback(paint, XtNregionCallback, (XtCallbackProc)prCallback, 
  1455.                 (XtPointer)rotateMenu[i].widget);
  1456.         prCallback(paint, rotateMenu[i].widget, False);
  1457.     }
  1458.     
  1459.     XtAddCallback(regionMenu[RG_ROTATE].widget, 
  1460.             XtNcallback, (XtCallbackProc)rotate, (XtPointer)paint);
  1461.     XtAddCallback(paint, XtNregionCallback, (XtCallbackProc)prCallback, 
  1462.             (XtPointer)regionMenu[RG_ROTATE].widget);
  1463.     prCallback(paint, regionMenu[RG_ROTATE].widget, False);
  1464.     XtAddCallback(regionMenu[RG_RESET].widget, 
  1465.             XtNcallback, (XtCallbackProc)resetMat, (XtPointer)paint);
  1466.  
  1467. #ifdef RG_BOX
  1468.     XtAddCallback(regionMenu[RG_BOX].widget, 
  1469.             XtNcallback, (XtCallbackProc)nudgeBox, (XtPointer)paint);
  1470. #endif
  1471.     XtAddCallback(paint, XtNregionCallback, (XtCallbackProc)prCallback, 
  1472.             (XtPointer)regionMenu[RG_RESET].widget);
  1473.     prCallback(paint, regionMenu[RG_RESET].widget, False);
  1474.  
  1475.  
  1476.     form = XtVaCreateManagedWidget("form2", 
  1477.             formWidgetClass, pane,
  1478.             XtNskipAdjust, True,
  1479.             NULL);
  1480.  
  1481.     pattern = mkPatternArea(form, None, "primary", &pform, info);
  1482.     info->primaryBox = pattern;
  1483.  
  1484.     pattern = mkPatternArea(form, pform, "secondary", &pform, info);
  1485.     info->secondaryBox = pattern;
  1486.  
  1487.     info->primaryList   = None;
  1488.     info->secondaryList = None;
  1489.  
  1490.     /*
  1491.     **  Now construct the paletter area and set the
  1492.     **    primary and secondary selections correctly
  1493.     */
  1494.  
  1495.     makePaletteArea(info, rcInfo);
  1496.  
  1497.     XtVaGetValues(info->primaryBox, XtNchildren, &child, 
  1498.                     XtNnumChildren, &nchild,
  1499.                     NULL);
  1500.     XtVaGetValues(child[0], XtNradioData, &pData, NULL);
  1501.     XawToggleSetCurrent(info->primaryList, (XtPointer)pData);
  1502.  
  1503.     XtVaGetValues(info->secondaryBox, XtNchildren, &child, 
  1504.                     XtNnumChildren, &nchild,
  1505.                     NULL);
  1506.     if (nchild == 1)
  1507.         XtVaGetValues(child[0], XtNradioData, &pData, NULL);
  1508.     else
  1509.         XtVaGetValues(child[1], XtNradioData, &pData, NULL);
  1510.     XawToggleSetCurrent(info->secondaryList, (XtPointer)pData);
  1511.  
  1512.     XtManageChild(info->primaryBox);
  1513.     XtManageChild(info->secondaryBox);
  1514.  
  1515.     /*
  1516.     **  A few buttons for help...
  1517.     */
  1518.  
  1519.     add  = XtVaCreateManagedWidget("addPattern",
  1520.             commandWidgetClass, form,
  1521.             XtNfromHoriz, pform,
  1522.             XtNfromVert,  None,
  1523.             XtNleft, XtChainRight,
  1524.             XtNright, XtChainRight,
  1525.             XtNtop, XtChainTop,
  1526.             XtNbottom, XtChainTop,
  1527.             NULL);
  1528.     /*
  1529.     **  If we are on a small static colormap, we shouldn't be able to do an add. XXX
  1530.     */
  1531.     edit = XtVaCreateManagedWidget("addSolid",
  1532.             commandWidgetClass, form,
  1533.             XtNfromHoriz, pform,
  1534.             XtNfromVert,  add,
  1535.             XtNleft, XtChainRight,
  1536.             XtNright, XtChainRight,
  1537.             XtNtop, XtChainTop,
  1538.             XtNbottom, XtChainTop,
  1539.             NULL);
  1540.  
  1541.     if (edit != None)
  1542.         XtAddCallback(edit, XtNcallback, addSolidCallback, (XtPointer)info);
  1543.     XtAddCallback(add , XtNcallback, addPatternCallback, (XtPointer)info);
  1544.     XtAddCallback(paint, XtNdestroyCallback, destroyCallback, (XtPointer)info);
  1545.  
  1546.     AddDestroyCallback(shell, 
  1547.         (void (*)(Widget, void *, XEvent *))closeCallback,(void*)paint);
  1548.  
  1549.     SetIconImage(shell, False);
  1550.  
  1551.     XtRealizeWidget(shell);
  1552.  
  1553.     GraphicAdd(paint);
  1554.  
  1555.     return shell;
  1556. }
  1557.  
  1558. typedef struct cwi_s {
  1559.     Widget    paint;    
  1560.     void    *id;
  1561.     struct cwi_s    *next;
  1562. } CanvasWriteInfo;
  1563.  
  1564. static CanvasWriteInfo    *cwiHead = NULL;
  1565.  
  1566. void removeCWI(Widget w, CanvasWriteInfo *ci, XtPointer junk)
  1567. {
  1568.     CanvasWriteInfo    *cur = cwiHead, **pp = &cwiHead;
  1569.  
  1570.     while (cur != NULL && cur != ci) {
  1571.         pp = &cur->next;
  1572.         cur = cur->next;
  1573.     }    
  1574.  
  1575.     if (cur == NULL)
  1576.         return;
  1577.     *pp = cur->next;
  1578.     XtFree((XtPointer)ci);
  1579. }
  1580.  
  1581. void *GraphicGetReaderId(Widget paint)
  1582. {
  1583.     CanvasWriteInfo    *cur;
  1584.  
  1585.     paint = GetShell(paint);
  1586.  
  1587.     for (cur = cwiHead; cur != NULL && cur->paint != paint; cur = cur->next)
  1588.         ;
  1589.  
  1590.     if (cur == NULL)
  1591.         return NULL;
  1592.  
  1593.     return cur->id;
  1594. }
  1595.  
  1596. void GraphicOpenFile(Widget w, XtPointer fileArg, XtPointer imageArg)
  1597. {
  1598.     char        *file = (char *)fileArg;
  1599.     Image        *image = (Image *)imageArg;
  1600.     Colormap    cmap;
  1601.     Pixmap        pix;
  1602.     Widget        shell = makeGraphicShell(w);
  1603.     CanvasWriteInfo    *ci = XtNew(CanvasWriteInfo);
  1604.  
  1605.     ci->next  = cwiHead;
  1606.     cwiHead   = ci;
  1607.     ci->paint = shell;
  1608.     ci->id    = GetFileNameGetLastId();
  1609.  
  1610.     XtAddCallback(shell, XtNdestroyCallback, (XtCallbackProc)removeCWI, (XtPointer)ci);
  1611.  
  1612.     if (ImageToPixmap(image, shell, &pix, &cmap)) {
  1613.         /*
  1614.         **   If mask != None, set the mask region color to the BG color of the Canvas
  1615.         */
  1616.         if ((shell = graphicCreate(shell, 0, 0, -1, pix, cmap)) != None) {
  1617.             char    *cp = strrchr(file, '/');
  1618.             if (cp == NULL)
  1619.                 cp = file;
  1620.             else
  1621.                 cp++;
  1622.  
  1623.             XtVaSetValues(shell, XtNiconName, cp, XtNtitle, file, NULL);
  1624.         } else {
  1625.             XtDestroyWidget(shell);
  1626.         }
  1627.     } else {
  1628.         Notice(w, "Unable to create paint window with image");
  1629.         XtDestroyWidget(shell);
  1630.     }
  1631. }
  1632.  
  1633. static void doCreate(Widget wid, int width, int height, int zoom)
  1634. {
  1635.     graphicCreate(makeGraphicShell(wid), width, height, zoom, None, None);
  1636. }
  1637.  
  1638. void GraphicCreate(Widget wid, int value)
  1639. {
  1640.     int    width, height;
  1641.     
  1642.     switch (value) {
  1643.     case 0:
  1644.         GetDefaultWH(&width, &height);
  1645.         graphicCreate(makeGraphicShell(wid), width, height, -1, None, None);
  1646.         break;
  1647.     case 1:
  1648.         GetFileName(GetToplevel(wid), 0, NULL, GraphicOpenFile, NULL);
  1649.         break;
  1650.     case 2:
  1651.         SizeSelect(wid, None, doCreate);
  1652.         break;
  1653.     }
  1654. }
  1655.